TITLE: Deadlock with AutoRequest() WARNING! We have had several people fall prey to a rather subtle deadlock situation involving AutoRequest() and (usually) the MENUVERIFY mode of Intuition. Other Intuition xVERIFY modes have similar potential for deadlock as well. AutoRequest() is the Intuition function used to build simple Requesters -- usually used for error processing. It blocks the requesting task until the user responds by selecting an exit gadget of the requester. AutoRequest() is built on top of BuildSysRequest() which, currently, makes a new window and installs your requester in it. MENUVERIFY is the Intuition menu handling mode which causes Intuition to send a message to your task if your window is the Active window and the user presses the Menu button (the right-hand button) on the mouse. Intuition will hold off doing all normal interactive processing until you reply to that message. Your reply indicates either that you've done any clean-up processing and Intuition can go display the menu, or that you want Intuition to ignore this menu request and let you handle the Right Mouse Button (RMB) yourself this time. Your delay before replying should be short because the system appears hung to the user until you reply to Intuition. You must NOT call AutoRequest() while MENUVERIFY is in effect in any window controlled by your task. If you do so, and if your window becomes the Active window, then if the user presses the Menu button you will be in a deadlock. Your task can't procede because the user hasn't selected an exit gadget on the Requester. The user can't select that gadget because Intuition is stuck in MENUVERIFY waiting for your task to reply. Your task can't reply because it's blocked behind the Requester. The subtlety is that AmigaDOS may generate an AutoRequest() FOR YOU if an I/O error happens during an AmigaDOS call. If an I/O error occurs during an AmigaDOS I/O call, AmigaDOS looks at the pr_WindowPtr field of the Process structure for the process that generated the call. [An AmigaDOS Process is an EXEC Task plus a little extra context. See the dosextens.h or dosextens.i include files for info.] If that field is -1, then AmigaDOS returns the error to the requesting process in the normal fashion. If that field is >=0, then AmigaDOS puts up a system requester using the AutoRequest() facility. If pr_WindowPtr is 0, that requester is put up in a new window in the Workbench screen. If pr_WindowPtr is positive, then it is interpreted as a pointer to a Window structure -- usually the control window for your program. In the current implementation, AmigaDOS puts up the requester in a new window in the same screen as the specified window. Certain unlikely I/O errors are detected so deeply in the file system that their requesters can ONLY appear in the Workbench screen even if you have specified a window. The pr_WindowPtr field is inherited from your process creator. Normally it's 0 when your process starts. If you change the field, you must be sure to change it back before your program exits. This is because you may be running as a co-routine of a CLI in the CLI process context. If you leave the pointer set to a window that you've just closed, the CLI will probably crash the system the next time it gets an I/O error. Not all I/O errors will generate requesters. The ones that do are the ones that the user can be expected to correct. These include Write Protected disks and Wrong Disk in drive. For more information on this processing, see the AmigaDOS Technical Reference Manual chapter on DOS Data Structures. The upshot of all this is that you shouldn't do AmigaDOS I/O calls while you have MENUVERIFY set and a pr_WindowPtr of other than -1. If you do, there is a chance that AmigaDOS will be forced to put up a system requester. In that case, if the user is so unfortunate as to hit the Menu button, while your window is the Active window, you will be in deadlock. Note that if you intend to do ALL your own Right Mouse Button processing, you can set the RMBTRAP flag in your Window structure without concern about deadlocks. The value of the MENUVERIFY stuff is limited to those cases where you WANT Intuition to do Menu processing, but you don't want it to do so just now. For more information on all of this refer to the manual Intuition: The Amiga User Interface. PRELIMINARY INFORMATION... CURRENTLY UNDER REVIEW. DOESN'T DESCRIBE THE set mouse port FUNCTIONS. MAY CONTAIN MINOR INACCURACIES IN THE SAMPLE PROGRAM SEGMENT. (printed version available approx 11/18/85, reviewed and correct- ed). Rob Peck. Chapter 1 Input Device This chapter describes the Amiga input device, which is a combi- nation of three other devices: keyboard device, gameport device, and timer device. The input device merges separate input event streams from the keyboard, mouse, and timer into a single stream. This single stream can then be interpreted by the prioritized linked list of input handlers that are watching the input stream. 1.1. OVERVIEW The input device is automatically opened by AmigaDOS by any call to open the console device. When the input device is opened, a task, appropriately named ``input.device'', is started. The input device task communicates directly with the keyboard device to obtain raw key inputs. It also communicates with the gameport device to obtain mouse button and mouse movement events and with the timer device to obtain time events. In addition to these event streams, you can also directly input an event to the input device, to be fed to the handler chain. This topic is also covered below. The keyboard device is also accessible directly. However, while the input device task is operating, it attempts to retrieve all incoming keyboard events and add them to the input stream. The gameport device has two units available to it. As you view the Amiga looking at the gameport connectors, connector ``1'' is assigned as the primary mouse input for Intuition and contributes gameport input events to the input event stream. Connector ``2'' is handled by the other gameport unit and is currently unas- signed. Each unit of the gameport device is an exclusive access object, in that you can specify what type of controller is attached. It is then assumed that only one task is sending requests for input from that unit. While the input device task is running, that task expects to read the input from connector 1. Direct use of the gameport device is covered in a separate chapter of this manual. November 13, 1985 - 2 - The timer device provides time events for the input device. It also provides time interval reports for controlling key repeat rate and key repeat threshold. The timer device is a shared- access device and is described in its own separate section. 1.2. INPUT DEVICE COMMANDS The input device allows the following system functions: box; ci ci l l. COMMAND OPERATION = OpenDevice() Obtain shared use of the input device. CloseDevice() Relinquish use of the input device. DoIO() Initiate a command, and wait for it to complete. SendIO() Initiate a command, and return immediately. AbortIO() Abort a command already in the queue. Only the Start, Stop, Invalid, and Flush commands have been implemented for this device. All other commands are no- operations. The input device also supports the following device-specific com- mands: Table 1-1: Input Device Commands box; ci ci l l. I/O COMMAND OPERATION = IND_WRITEEVENT Propagate an input event stream to all dev- ices IND_ADDHANDLER Add an input-stream handler into the handler chain. IND_REMHANDLER Remove an input-stream handler from the handler chain. IND_SETTHRESH Set the repeating key hold-down time before repeat starts. IND_SETPERIOD Set the period at which a repeating key repeats. IND_SETMPORT Set the gameport port to which the mouse is connected. IND_SETTRIGGER Read conditions that must be met by a mouse before a pending read request will be satisfied. IND_SETMTYPE Set the type of device at the mouse port. The device-specific commands outlined above are described in the following paragraphs. A description of the contents of an input event is given first because the input device deals in input November 13, 1985 - 3 - events. An input event is a data structure that describes: o the class of the event-often describes the device that generated the event o the subclass of the event-space for more information if needed o the code-keycode if keyboard, button information if mouse, others o a qualifier such as ``ALT key also down'', ``key repeat active'' o a position field which contains a data address or a mouse position count. o a time stamp, showing the sequence in which events have occurred o a link-field by which input events are linked together The various types of input events are listed in the include-file devices/inputevent.h. That information is not repeated here. You can find more information about input events in the chapters titled ``Gameport Device'' and ``Console Device''. There is a difference between simply receiving an input event from a device (gameport, keyboard, or console) and actually becoming a handler of an input event stream. A handler is a rou- tine that is passed an input event, and it is up to the handler to decide if it can process the input event. If the handler does not recognize the event, it passes the address of the event as a return value. Because of the input event field called ie_NextEvent, it is pos- sible for the input event to be a pointer to the first event in a linked list of events to be handled. Thus the handler should be designed to handle multiple events if such a link is used. Note that handlers can, themselves, generate new linked lists of events which can be passed down to lower priority handlers. You add a handler to the chain by the command IND_ADDHANDLER. Assuming that you have a properly initialized an IOStdReq block as a result of a call to OpenDevice() (for the input device), here is a typical C-language call to the IND_ADDHANDLER function: November 13, 1985 - 4 - struct Interrupt handlerStuff; handlerStuff.is_Data = &hsData; /* address of its data area */ handlerStuff.is_Code = myhandler; /* address of entry point to handler */ handlerStuff.is_Node.ln_Pri = 51; /* set the priority one step higher than * Intution, so that our handler enters * the chain ahead of Intuition. */ inputRequestBlock.io_Command = IND_ADDHANDLER; inputRequestBlock.io_Data = &handlerStuff; DoIO(&inputRequestBlock); Notice from the above that Intuition is one of the input device handlers and normally distributes all of the input events. Intuition inserts itself at priority position 50. You can choose the position in the chain at which your handler will be inserted by setting the priority field in the list-node part of the inter- rupt data structure you are feeding to this routine. Note also that any processing time expended by a handler sub- tracts from the time available before the next event happens. Therefore, handlers for the input stream must be fast. Rules for Input Device Handlers The following rules should be followed when you are designing an input handler: 1. If an input handler is capable of processing a specific kind of an input event and that event has no links (ie_NextEvent = 0), the handler can end the handler chain by returning a NULL (0) value. 2. If there are multiple events linked together, the handler can feel free to delink an event from the input event chain, thereby passing a shorter list of events to subse- quent handlers. The starting address of the modified list is the return value. 3. If a handler wishes to add new events to the chain that it passes to a lower priority handler, it may initialize memory to contain the new event or event chain. The handler, when it again gets control on the next round of event handling, should assume nothing about the current contents of the memory blocks it attached to the event chain. Lower priority handlers may have modified the November 13, 1985 - 5 - memory as they handled their part of the event. The handler that allocates the memory for this purpose should keep track of the starting address and the size of this memory chunk so that the memory can be returned to the free memory list when it is no longer needed. Your routine should be structured so that it can be called as though from the following assembler language statement: newEventChain = yourHandlerCode(oldEventChain, yourHandlerData); where: o yourHandlerCode is the entry point to your routine, o oldEventChain is the starting address for the current chain of input events, and o newEventChain is the starting address of an event chain which you are passing to the next handler, if any. A NULL (0) value terminates the handling. Memory that you use to describe a new input event that you've added to the event chain is available for re-use or deallocation when the handler is called again or after the IND_REMHANDLER com- mand for the handler is complete. Because IND_ADDHANDLER installs a handler in any position in the handler chain, it can, for example, ignore specific types of input events as well as act upon and modify existing streams of input. It can even create new input events for Intuition or other programs to interpret. You remove a handler from the handler chain with the command IND_REMHANDLER. Assuming that you have a properly initialized IOStdReq block as a result of a call to OpenDevice() (for the input device) and you have already added the handler using IND_ADDHANDLER, here is a typical C-language call to the IND_REMHANDLER function: inputRequestBlock.io_Command = IND_REMHANDLER; inputRequestBlock.io_Da